home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Online / NNTPd / xmit / get_tcp_conn.c next >
Encoding:
C/C++ Source or Header  |  2002-11-17  |  7.6 KB  |  331 lines

  1. #ifndef lint
  2. static char * rcsid = "$Id: get_tcp_conn.c,v 1.8 1994/11/17 16:43:05 sob Exp sob $";
  3. #endif
  4. #define USE_KEEPALIVES /* XXX should be in ../conf.h */
  5.  
  6. /*
  7. ** Routines to open a TCP connection
  8. **
  9. ** New version that supports the old (pre 4.2 BSD) socket calls,
  10. ** and systems with the old (pre 4.2 BSD) hostname lookup stuff.
  11. ** Compile-time options are:
  12. **
  13. **    USG        - you're on System III/V (you have my sympathies)
  14. **    NONETDB        - old hostname lookup with rhost()
  15. **    OLDSOCKET    - different args for socket() and connect()
  16. **
  17. ** Erik E. Fair <fair@ucbarpa.berkeley.edu>
  18. **
  19. */
  20.  
  21. #include "../conf.h"
  22. #include <sys/types.h>
  23. #include <sys/socket.h>
  24. #include <netinet/in.h>
  25. #include <ctype.h>
  26. #include <stdio.h>
  27. #include "get_tcp_conn.h"
  28. #ifndef    NONETDB
  29. #include <netdb.h>
  30. #endif    /* NONETDB */
  31.  
  32. extern    int    errno;
  33. extern    char    *Pname;
  34. extern    char    *errmsg();
  35. #ifndef BSD_44
  36. #ifndef    htons
  37. extern    u_short    htons();
  38. #endif    /* htons */
  39. #endif
  40. #ifndef    NONETDB
  41. extern    char    *inet_ntoa();
  42. extern    u_long    inet_addr();
  43. #else
  44. /*
  45.  * inet_addr for EXCELAN (which does not have it!)
  46.  *
  47.  */
  48. u_long
  49. inet_addr(cp)
  50. register char    *cp;
  51. {
  52.     u_long val, base, n;
  53.     register char c;
  54.      u_long octet[4], *octetptr = octet;
  55. #ifndef    htonl
  56.     extern    u_long    htonl();
  57. #endif    /* htonl */
  58. again:
  59.     /*
  60.      * Collect number up to ``.''.
  61.      * Values are specified as for C:
  62.      * 0x=hex, 0=octal, other=decimal.
  63.      */
  64.     val = 0; base = 10;
  65.     if (*cp == '0')
  66.         base = 8, cp++;
  67.     if (*cp == 'x' || *cp == 'X')
  68.         base = 16, cp++;
  69.     while (c = *cp) {
  70.         if (isdigit(c)) {
  71.             val = (val * base) + (c - '0');
  72.             cp++;
  73.             continue;
  74.         }
  75.         if (base == 16 && isxdigit(c)) {
  76.             val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
  77.             cp++;
  78.             continue;
  79.         }
  80.         break;
  81.     }
  82.     if (*cp == '.') {
  83.         /*
  84.          * Internet format:
  85.          *    a.b.c.d
  86.          *    a.b.c    (with c treated as 16-bits)
  87.          *    a.b    (with b treated as 24 bits)
  88.          */
  89.         if (octetptr >= octet + 4)
  90.             return (-1);
  91.         *octetptr++ = val, cp++;
  92.         goto again;
  93.     }
  94.     /*
  95.      * Check for trailing characters.
  96.      */
  97.     if (*cp && !isspace(*cp))
  98.         return (-1);
  99.     *octetptr++ = val;
  100.     /*
  101.      * Concoct the address according to
  102.      * the number of octet specified.
  103.      */
  104.     n = octetptr - octet;
  105.     switch (n) {
  106.  
  107.     case 1:                /* a -- 32 bits */
  108.         val = octet[0];
  109.         break;
  110.  
  111.     case 2:                /* a.b -- 8.24 bits */
  112.         val = (octet[0] << 24) | (octet[1] & 0xffffff);
  113.         break;
  114.  
  115.     case 3:                /* a.b.c -- 8.8.16 bits */
  116.         val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
  117.             (octet[2] & 0xffff);
  118.         break;
  119.  
  120.     case 4:                /* a.b.c.d -- 8.8.8.8 bits */
  121.         val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
  122.               ((octet[2] & 0xff) << 8) | (octet[3] & 0xff);
  123.         break;
  124.  
  125.     default:
  126.         return (-1);
  127.     }
  128.     val = htonl(val);
  129.     return (val);
  130. }
  131.  
  132. char *
  133. inet_ntoa(in)
  134. struct in_addr in;
  135. {
  136.     static char address[20];
  137.  
  138.     sprintf(address, "%u.%u.%u.%u",
  139.              (in.s_addr>>24)&0xff,
  140.              (in.s_addr>>16)&0xff,
  141.              (in.s_addr>>8 )&0xff,
  142.              (in.s_addr    )&0xff);
  143.     return(address);
  144. }
  145. #endif    /* NONETDB */
  146.  
  147. /*
  148. ** Take the name of an internet host in ASCII (this may either be its
  149. ** official host name or internet number (with or without enclosing
  150. ** backets [])), and return a list of internet addresses.
  151. **
  152. ** returns NULL for failure to find the host name in the local database,
  153. ** or for a bad internet address spec.
  154. */
  155. u_long **
  156. name_to_address(host)
  157. char    *host;
  158. {
  159.     static    u_long    *host_addresses[2];
  160.     static    u_long    haddr;
  161.  
  162.     if (host == (char *)NULL) {
  163.         return((u_long **)NULL);
  164.     }
  165.  
  166.     host_addresses[0] = &haddr;
  167.     host_addresses[1] = (u_long *)NULL;
  168.  
  169.     /*
  170.     ** Is this an ASCII internet address? (either of [10.0.0.78] or
  171.     ** 10.0.0.78). We get away with the second test because hostnames
  172.     ** and domain labels are not allowed to begin in numbers.
  173.     ** (cf. RFC952, RFC882).
  174.     */
  175.     if (*host == '[' || isdigit(*host)) {
  176.         char    namebuf[128];
  177.         register char    *cp = namebuf;
  178.  
  179.         /*
  180.         ** strip brackets [] or anything else we don't want.
  181.         */
  182.         while(*host != '\0' && cp < &namebuf[sizeof(namebuf)]) {
  183.             if (isdigit(*host) || *host == '.')
  184.                 *cp++ = *host++;    /* copy */
  185.             else
  186.                 host++;            /* skip */
  187.         }
  188.         *cp = '\0';
  189.         haddr = inet_addr(namebuf);
  190.         return(&host_addresses[0]);
  191.     } else {
  192. #ifdef    NONETDB
  193.         extern    u_long    rhost();
  194.  
  195.         /* lint is gonna bitch about this (comparing an unsigned?!) */
  196.         if ((haddr = rhost(&host)) == FAIL)
  197.             return((u_long **)NULL);    /* no such host */
  198.         return(&host_addresses[0]);
  199. #else
  200.         struct hostent    *hstp = gethostbyname(host);
  201.  
  202.         if (hstp == NULL) {
  203.             return((u_long **)NULL);    /* no such host */
  204.         }
  205.  
  206.         if (hstp->h_length != sizeof(u_long))
  207.             abort();    /* this is fundamental */
  208. #ifndef    h_addr
  209.         /* alignment problems (isn't dbm wonderful?) */
  210.         bcopy((caddr_t)hstp->h_addr, (caddr_t)&haddr, sizeof(haddr));
  211.         return(&host_addresses[0]);
  212. #else
  213.         return((u_long **)hstp->h_addr_list);
  214. #endif    /* h_addr */
  215. #endif    /* NONETDB */
  216.     }
  217. }
  218.  
  219. /*
  220. ** Get a service port number from a service name (or ASCII number)
  221. **
  222. ** Return zero if something is wrong (that's a reserved port)
  223. */
  224. #ifdef    NONETDB
  225. static struct Services {
  226.     char    *name;
  227.     u_short    port;
  228. } Services[] = {
  229.     {"nntp",    IPPORT_NNTP},        /* RFC977 */
  230.     {"smtp",    IPPORT_SMTP},        /* RFC821 */
  231.     {"name",    IPPORT_NAMESERVER},    /* RFC881, RFC882, RFC883 */
  232.     {"time",    IPPORT_TIMESERVER},    /* RFC868 */
  233.     {"echo",    IPPORT_ECHO},        /* RFC862 */
  234.     {"discard",    IPPORT_DISCARD},    /* RFC863 */
  235.     {"daytime",    IPPORT_DAYTIME},    /* RFC867 */
  236.     {"login",    IPPORT_LOGINSERVER},    /* N/A - 4BSD specific */
  237. };
  238. #endif    /* NONETDB */
  239.  
  240. u_short
  241. gservice(serv, proto)
  242. char    *serv, *proto;
  243. {
  244.     if (serv == (char *)NULL || proto == (char *)NULL)
  245.         return((u_short)0);
  246.  
  247.     if (isdigit(*serv)) {
  248.         return(htons((u_short)(atoi(serv))));
  249.     } else {
  250. #ifdef    NONETDB
  251.         register int    i;
  252.  
  253.         for(i = 0; i < (sizeof(Services) / sizeof(struct Services)); i++) {
  254.             if (strcmp(serv, Services[i].name) == 0)
  255.                 return(htons(Services[i].port));
  256.         }
  257.         return((u_short)0);
  258. #else
  259.         struct servent    *srvp = getservbyname(serv, proto);
  260.  
  261.         if (srvp == (struct servent *)NULL)
  262.             return((u_short)0);
  263.         return((u_short)srvp->s_port);
  264. #endif    /* NONETDB */
  265.     }
  266. }
  267.  
  268. /*
  269. ** given a host name (either name or internet address) and service name
  270. ** (or port number) (both in ASCII), give us a TCP connection to the
  271. ** requested service at the requested host (or give us FAIL).
  272. */
  273. get_tcp_conn(host, serv)
  274. char    *host, *serv;
  275. {
  276.     register int    sock;
  277.     u_long    **addrlist;
  278.     struct sockaddr_in    sadr;
  279. #ifdef    OLDSOCKET
  280.     struct sockproto    sp;
  281.  
  282.     sp.sp_family    = (u_short)AF_INET;
  283.     sp.sp_protocol    = (u_short)IPPROTO_TCP;
  284. #endif    /* OLDSOCKET */
  285.  
  286.     if ((addrlist = name_to_address(host)) == (u_long **)NULL) {
  287.         return(NOHOST);
  288.     }
  289.  
  290.     sadr.sin_family = (u_short)AF_INET;    /* Only internet for now */
  291.     if ((sadr.sin_port = gservice(serv, "tcp")) == 0)
  292.         return(NOSERVICE);
  293.  
  294.     for(; *addrlist != (u_long *)NULL; addrlist++) {
  295.         bcopy((caddr_t)*addrlist, (caddr_t)&sadr.sin_addr,
  296.             sizeof(sadr.sin_addr));
  297.  
  298. #ifdef    OLDSOCKET
  299.         if ((sock = socket(SOCK_STREAM, &sp, (struct sockaddr *)NULL, 0)) < 0)
  300.             return(FAIL);
  301.  
  302.         if (connect(sock, (struct sockaddr *)&sadr) < 0) {
  303. #else
  304.         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  305.             return(FAIL);
  306.  
  307.         if (connect(sock, (struct sockaddr *)&sadr, sizeof(sadr)) < 0) {
  308. #endif    /* OLDSOCKET */
  309.             int    e_save = errno;
  310.  
  311.             fprintf(stderr, "%s: %s [%s]: %s\n", Pname, host,
  312.                 inet_ntoa(sadr.sin_addr), errmsg(errno));
  313.             (void) close(sock);    /* dump descriptor */
  314.             errno = e_save;
  315.         } else
  316.                                     {
  317. #ifdef USE_KEEPALIVES
  318.                                       int on = 1;
  319.                                       if (setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(char *)&on,sizeof(on)) < 0)
  320.                                        { int e_save;
  321.                                      e_save = errno;
  322.                                      fprintf(stderr,"%s: %s [%s]: setsockopt KEEPALIVE: %s\n",Pname,host,inet_ntoa(sadr.sin_addr),errmsg(errno));
  323.                                      /* don't bother erroring out, just note it and ignore it */
  324.                                        }
  325. #endif
  326.                                       return(sock);
  327.                                     }
  328.     }
  329.     return(FAIL);
  330. }
  331.